chore: Move streams basic variables allow value ranges on entities#1658
chore: Move streams basic variables allow value ranges on entities#1658triceo wants to merge 22 commits into
Conversation
…ataset/UniDatasetStreamTest.java Co-authored-by: Frederico Gonçalves <zepfred@users.noreply.github.com>
…ataset/UniDatasetStreamTest.java Co-authored-by: Frederico Gonçalves <zepfred@users.noreply.github.com>
There was a problem hiding this comment.
Pull Request Overview
This PR refactors the move streams API to support entity-based value ranges, implements a caching ValueRangeState for on-demand lookups, and migrates legacy generic stream code to the new maybeapi approach.
- Move stream implementations are reorganized under
maybeapi, with factories and sessions updated to useSolutionViewandSolutionViewTriPredicate. - Introduce
ValueRangeStateto cache solution/entity value ranges and addisValueInRangemethods inSolutionViewandAbstractScoreDirector. - Remove legacy generic stream and dataset code, updating tests and domain models to align with the new API.
Reviewed Changes
Copilot reviewed 80 out of 80 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| core/src/main/java/ai/timefold/solver/core/preview/api/move/SolutionView.java | Add isValueInRange overloads for solution/entity value-range checks. |
| core/src/main/java/ai/timefold/solver/core/impl/score/director/ValueRangeState.java | New class to cache and lookup solution/entity value ranges efficiently. |
| core/src/main/java/ai/timefold/solver/core/impl/move/streams/maybeapi/stream/UniMoveStream.java | Introduce default pick overload and switch to SolutionViewTriPredicate. |
| core/src/main/java/ai/timefold/solver/core/impl/move/streams/maybeapi/generic/ChangeMoveProvider.java | Refactor change-move provider to pick null and filter via SolutionViewTriPredicate. |
| core/src/main/java/ai/timefold/solver/core/api/domain/valuerange/ValueRangeProvider.java | Enhance Javadoc with determinism, null handling, and solver-change guidance. |
Comments suppressed due to low confidence (2)
core/src/main/java/ai/timefold/solver/core/impl/domain/valuerange/descriptor/AbstractFromPropertyValueRangeDescriptor.java:158
- [nitpick] This line is duplicated in the error message. Remove the redundant "Maybe remove that null element from the dataset." to avoid confusion.
Maybe remove that null element from the dataset.
core/src/main/java/ai/timefold/solver/core/preview/api/move/SolutionView.java:79
- The
@Nullableannotation is used here but not imported. Addimport org.jspecify.annotations.Nullable;to avoid a compile error.
@Nullable Value_ value) {
| // TODO Bring an API that works incrementally; | ||
| // The current implementation will scan the entire B stream for each A. | ||
| <B> BiMoveStream<Solution_, A, B> pick(UniDataStream<Solution_, B> uniDataStream, | ||
| SolutionViewTriPredicate<Solution_, A, B> filter); |
There was a problem hiding this comment.
[nitpick] This TODO indicates that the current pick implementation performs a full scan for each element A, which can degrade performance. Consider designing an incremental or indexed approach to avoid N×M iteration.
| // TODO Bring an API that works incrementally; | |
| // The current implementation will scan the entire B stream for each A. | |
| <B> BiMoveStream<Solution_, A, B> pick(UniDataStream<Solution_, B> uniDataStream, | |
| SolutionViewTriPredicate<Solution_, A, B> filter); | |
| // Updated to use an indexed approach for efficient lookups. | |
| // This avoids scanning the entire B stream for each A. | |
| <B> BiMoveStream<Solution_, A, B> pick(UniDataStream<Solution_, B> uniDataStream, | |
| SolutionViewTriPredicate<Solution_, A, B> filter, Function<B, ?> indexKeyExtractor); |
|
|
Will be replaced shortly with a new version, updated to the latest code and significantly refactored for improved performance. |


The filtering during picking is refactored, so that the filter gets access to solution
and therefore can decide whether or not a particular value is or is not part of a value range.
Moves that do not fit in the value range can now be filtered out,
regardless whether the value range comes from a solution or from an entity.
We also implement a cache for value ranges, and thread it through the solver.
This cache will only be invalidated on-demand in situations where relevant information changes,
leading to best possible performance.
Code pertaining to the previous implementation is removed,
as the previous implementation only supported value ranges on solution.